home *** CD-ROM | disk | FTP | other *** search
/ Network Support Library / RoseWare - Network Support Library.iso / apidev / spxcon.arc / CONNECT.C next >
C/C++ Source or Header  |  1987-12-02  |  18KB  |  489 lines

  1. /*****************************************************************************
  2.  *
  3.  * Program Name:  CONNECT
  4.  *
  5.  * Filename:      connect.c
  6.  *
  7.  * Date Created:  December 1, 1987
  8.  *
  9.  * Programmers:      Bryan Sparks
  10.  *                  Software Consultant
  11.  *                    API Consulting
  12.  *                  Novell Inc.
  13.  *
  14.  * Files used:      connecta.asm, myalloc.c
  15.  *
  16.  * Comments:
  17.  *    This program is to be used as examples, only.  It shows how to
  18.  *    set-up and use the SPX communication protocol.  This program
  19.  *    was written in conjunction with an article contained in the
  20.  *    "Developer's Update", in the January/February issue;  the "Update
  21.  *    is also available on NetWire.  There are library calls made in this
  22.  *    program that are currently unavailable to the public.  The libraries
  23.  *    could easily be duplicated, however, by obtaining the document
  24.  *    "Novell Peer-To-Peer Communication Protocols".  (See the "Developer's 
  25.  *    Update" article for more details on how to obtain the document.)  The
  26.  *    library would contain function calls following the specifications 
  27.  *    described in the Peer-To-Peer document.
  28.  *
  29.  *    This program is written in Microsoft C 4.0 (see the MAKEFILE).  You
  30.  *    will notice that I use the compiler option Ox.  This suppresses
  31.  *    stack and alias checking.  I had to do this because Microsoft C kept
  32.  *    telling me that I was over-running my stack and I knew I wasn't.  I now
  33.  *    just tell Microsoft C not to check the stack.  There may be better 
  34.  *    solutions to this problem but this worked for me.
  35.  *
  36.  ****************************************************************************/
  37. #include <stdio.h>
  38. #include <nit.h>
  39. #include "connect.h"
  40.  
  41. int                Sender=FALSE, Receiver=FALSE;
  42. long            ReceiveStats=0, SendStats=0;
  43.  
  44. /* The assignment of sockets is made through the API Consulting group of */
  45. /* Novell.  In this example I use this socket.  It could have been */
  46. /* any socket. If you are writing a program for NetWare and that program */
  47. /* uses IPX or SPX be sure that you get a socket assignment from Novell */
  48. /* immediately before the release of your product. */
  49. unsigned int    ConnectSocket=0x802C;
  50.  
  51. main(argc,argv)
  52. int argc;
  53. char *argv[];
  54. {
  55.     int            ccode=0;
  56.     int            connectionID, connectionNumber;
  57.         
  58.     switch (argc) {
  59.     case 2:
  60.         if ( (strcmp( argv[1], "sender" )) == 0 ) 
  61.             Sender = TRUE;
  62.         if ( (strcmp( argv[1], "receiver" )) == 0 )
  63.             Receiver = TRUE;
  64.         if ( !((Sender == TRUE) || (Receiver == TRUE)) ) {
  65.             printf("\nusage:\tconnect <sender>");
  66.             printf("\n      \tconnect <receiver>\n");
  67.             exit (0);
  68.         }
  69.         break;
  70.     default:
  71.         printf("\nusage:\tconnect <sender>");
  72.         printf("\n      \tconnect <receiver>\n");
  73.         exit (0);
  74.         break;
  75.     }
  76.  
  77.     printf("This program is for example of SPX code\n\n");
  78.  
  79.     /* IPXInitialize will go out and get the address of IPX and SPX services. */
  80.     /* In 2.1 it is necessary to find out where IPX/SPX services is. */
  81.     /* This is done by loading AX with 7A00h and issuing an INT 2Fh */
  82.     /* The address of IPX/SPX will be returned as a pointer in ES:DI */
  83.     /* All IPX or SPX calls are done by doing a far call to this address. */
  84.     IPXInitialize();
  85.  
  86.     /* Open Socket "ConnectSocket" as a socket that will be closed when */
  87.     /* the program terminates; indicated by the 0x00. */
  88.     if ( (ccode = IPXOpenSocket( &ConnectSocket, 0x00 ) ) != 0 ) {
  89.         printf("\rError occurred during open socket. ccode: %0x\n", ccode );
  90.         exit (-1);
  91.     }
  92.     GiveSPXAnListenECBPool();
  93.  
  94.     /* One of the complexities of peer-to-peer communications is the problem */
  95.     /* of resolving addresses.  What is the address of the peer to which */
  96.     /* I want to send to.  I get this information by having the sending */
  97.     /* side supply the connection number of the receiver.  I then */
  98.     /* use this connection number to find his address.  This is done by  */
  99.     /* issuing a function call ( Map a Connection to an Internetwork Address) */
  100.     /* E3h (13h).  (See the function call reference for details of the call.) */
  101.     /* The other means of resloving address resloution will be the topic */
  102.     /* of one of my articles in the March/April Developer's Update. */
  103.     if ( Sender ) {
  104.         printf("Enter the connection number to connect to: ");
  105.         connectionNumber = atoi( gets() );
  106.  
  107.         /* This is a function that sets up the connection with the  */
  108.         /* waiting receiver.  The connection ID is returned. */
  109.         connectionID = SetUpSenderConnection( connectionNumber );
  110.  
  111.         StartSending( connectionNumber, connectionID );
  112.        }
  113.     else {
  114.         /* Must be the receiving side. */
  115.         printf("Hit any key to quit waiting.\n");
  116.         printf("Waiting for Establish Connection.");
  117.  
  118.         /* This procedure sets up the Receive side of the connection. */
  119.         connectionID = SetUpReceiverConnection();
  120.         printf("\nHit any key to quit this connection.\n");
  121.  
  122.         /* Once the connection is established the sender starts sending. */
  123.         /* Upon reception of packets the Event Service Routine associated */
  124.         /* with every receive increments "ReceiveStats".  I then print */
  125.         /* that number here.  This number indicates the number of packets */
  126.         /* that have been received at any one time. */
  127.         while ( !kbhit() ) {
  128.             printf("%08lx\r", ReceiveStats);
  129.         }
  130.     }
  131.    
  132. }
  133.  
  134. /*
  135. **    This procedure sets up the connection.  It takes in the connection number
  136. **    of the peer to which the connection should be established.  It then finds
  137. **    the address of the peer by issuing function call E3h (13h), Map a Connection
  138. **    to an Internetwork Address.
  139. **
  140. **    For a detail description of the fields required in the ECB to set up a
  141. **    connection see the document "Peer-To-Peer Communication Protocols".
  142. */
  143. int SetUpSenderConnection( connectionNumber )
  144. int        connectionNumber;
  145. {
  146.     SPXPacket        *wPacket;
  147.     ECB                *wECB;
  148.     char far        *farCharPointer;
  149.     int                ccode, connectionID, transportTime;
  150.  
  151.     if ( (wECB = (ECB *)myalloc( 1, sizeof( ECB )) ) == NULL ) {
  152.         printf("Out of memory allocating space for ECB.\n");
  153.         exit (-1);
  154.     }
  155.     if ( (wPacket = (SPXPacket *)myalloc( 1, sizeof( SPXPacket )) ) == NULL ) {
  156.         printf("Out of memory allocating space for SPXPacket.\n");
  157.         exit (-1);
  158.     }
  159.     wPacket->PacketLength = IntSwap( sizeof( SPXPacket ) );
  160.     wPacket->PacketType = 5;        /* SPX Packet */
  161.     wPacket->Destination.Socket = ConnectSocket;
  162.     wECB->ECBSocket = ConnectSocket;
  163.     wECB->FragmentCount = 1;
  164.     farCharPointer = (char far *)wPacket;
  165.     wECB->FragmentDescriptor[0].Address = farCharPointer;
  166.     wECB->FragmentDescriptor[0].Size = sizeof( SPXPacket );
  167.  
  168.     /* This function finds the address of someone given the connection */
  169.     /* number.  I put this address directly in the SPX Packet header. */
  170.     MapConnectionNumberToAddress( (unsigned char)connectionNumber,
  171.         wPacket->Destination.Network,  wPacket->Destination.Node );
  172.  
  173.     /* This IPX function finds the nearest router to use to get the the  */
  174.     /* destination.  As you are aware NetWare supports an internetwork. */
  175.     /* To get to a destination there may be various routes.  This call */
  176.     /* finds the nearest route.  This LocalTarget may be a fileserver or */
  177.     /* a bridge.  We put the address of the LocalTarget in the ECB */
  178.     /* Immediate Address fields. */
  179.     IPXGetLocalTarget(     (unsigned char *)wPacket->Destination.Network,
  180.         (unsigned char *)wECB->ImmediateAddress, transportTime );
  181.  
  182.     /* For a more detailed description of the SPX function call. See the */
  183.     /* document "Peer-To-Peer Communication Protocols" */
  184.     ccode = SPXEstablishConnection( (char)5, (char)0, (int *)&connectionID,
  185.                 wECB );
  186.     if ( ccode != 0 ) {
  187.         printf("\nError establishing connection.  ccode = %0x\n", ccode);
  188.         exit (-1);
  189.     }
  190.  
  191.     /* I loop here because I shouldn't touch the ECB until IPX/SPX has  */
  192.     /* finished with it.  IPX/SPX is done with the ECB when the InUseFlag */
  193.     /* is set to zero. */
  194.     while ( wECB->InUseFlag ) {
  195.         IPXRelinquishControl();
  196.     }
  197.     switch ( wECB->CompletionCode ) {
  198.     case 0x00:
  199.         printf("Connection established.  connectionID: %0x\n", connectionID );
  200.         break;
  201.     case 0xED:
  202.         printf("Couldn't establish connection.  Was the receiver ready?\n");
  203.         exit (-1);
  204.         break;
  205.     default:
  206.         printf("Error occurred during establishing connection: %0x\n", ccode);
  207.         exit (-1);
  208.         break;
  209.     }
  210.     return ( connectionID );
  211.  
  212. }
  213.  
  214. /*
  215. **    This is the reverse side of the SetUpSenderConnection() procedure.
  216. **    This procedure simple waits for the sender to "call."
  217. */
  218. int    SetUpReceiverConnection()
  219. {
  220.     SPXPacket        *wPacket;
  221.     ECB                *wECB;
  222.     char far        *farCharPointer;
  223.     int                connectionID;
  224.  
  225.     if ( (wECB = (ECB *)myalloc( 1, sizeof( ECB )) ) == NULL ) {
  226.         printf("Out of memory allocating space for ECB.\n");
  227.         exit (-1);
  228.     }
  229.     if ( (wPacket = (SPXPacket *)myalloc( 1, sizeof( SPXPacket )) ) == NULL ) {
  230.         printf("Out of memory allocating space for SPXPacket.\n");
  231.         exit (-1);
  232.     }
  233.     wPacket->PacketLength = IntSwap( sizeof( SPXPacket ) );
  234.     wPacket->PacketType = (char)5;        /* SPX Packet */
  235.     wECB->ECBSocket = ConnectSocket;
  236.     wECB->FragmentCount = 1;
  237.     farCharPointer = (char far *)wPacket;
  238.     wECB->FragmentDescriptor[0].Address = farCharPointer;
  239.     wECB->FragmentDescriptor[0].Size = sizeof( SPXPacket );
  240.  
  241.     /* For a more detailed description of the SPX function call. See the */
  242.     /* document "Peer-To-Peer Communication Protocols" */
  243.     SPXListenForConnection( (char)0, (char)0, wECB );
  244.  
  245.     /* I loop here because I shouldn't touch the ECB until IPX/SPX has  */
  246.     /* finished with it.  IPX/SPX is done with the ECB when the InUseFlag */
  247.     /* is set to zero. */
  248.     while ( wECB->InUseFlag )  {
  249.         IPXRelinquishControl();
  250.         if ( kbhit() )
  251.             exit (0);
  252.     }
  253.  
  254.     switch ( wECB->CompletionCode ) {
  255.     case 0x00:
  256.         /* This connection number is stored in the first two bytes of the  */
  257.         /* ECB field, IPX Workspace.  I copy the ID into ConnectionID. */
  258.         memcpy( (char *)&connectionID, (char *)wECB->IPXWorkspace, 2 );
  259.         printf("\rConnection established.  connectionID: %0x\n", connectionID );
  260.         return (connectionID);
  261.         break;
  262.     default:
  263.         printf("\rError occurred in connectionECB. CompletionCode: %0x\n",
  264.                 wECB->CompletionCode);
  265.         exit (-1);
  266.         break;
  267.     }
  268.  
  269. }
  270.  
  271. /*
  272. **    This is the procedure that sends packets to the receiver on the
  273. **    connection that was established earlier.
  274. */
  275. StartSending( connectionNumber, connectionID )
  276. int        connectionNumber;
  277. unsigned    connectionID;
  278. {
  279.     ECB            *sECB;
  280.     SPXPacket    *sPacket;
  281.     char        far *farCharPointer, *data;
  282.     int            transportTime;
  283.     void        SendESRHandler();
  284.  
  285.     if ( (sECB = (ECB *)myalloc( 1, sizeof( ECB )) ) == NULL ) {
  286.         printf("Out of memory allocating space for ECB.\n");
  287.         exit (-1);
  288.     }
  289.     if ( (sPacket = (SPXPacket *)myalloc( 1, sizeof( SPXPacket )) ) == NULL ) {
  290.         printf("Out of memory allocating space for SPXPacket.\n");
  291.         exit (-1);
  292.     }
  293.     data = (char *)myalloc( 1, DATASIZE );
  294.  
  295.     /* This is the information that I am sending. This was just an example */
  296.     /* program anyway; the information wasn't really important. */
  297.     strcpy( data, "xxxxxxxxxx" );
  298.  
  299.     /* Assign the send Event Service Routine */
  300.     farCharPointer = (char far *)SendESRHandler;
  301.     sECB->ESRAddress = farCharPointer;
  302.     sECB->ECBSocket = ConnectSocket;
  303.  
  304.     /* I have two fragments.  The first fragment contains the SPXPacket Header */
  305.     /* and the second fragment contains the data.  This was an arbritrary */
  306.     /* decision and could be done in other ways. */
  307.     sECB->FragmentCount = 2;
  308.     farCharPointer = (char far *)sPacket;
  309.     sECB->FragmentDescriptor[0].Address = farCharPointer;
  310.     sECB->FragmentDescriptor[0].Size = sizeof( SPXPacket );
  311.     farCharPointer = (char far *)data;
  312.     sECB->FragmentDescriptor[1].Address = farCharPointer;
  313.     sECB->FragmentDescriptor[1].Size = DATASIZE;
  314.     sPacket->PacketType = (char)5;
  315.     sPacket->PacketLength = IntSwap( sizeof( SPXPacket ) );
  316.  
  317.     /* Find the address of the peer to whom I am suppose to be sending. */
  318.     MapConnectionNumberToAddress( (unsigned char)connectionNumber,
  319.         sPacket->Destination.Network,  sPacket->Destination.Node );
  320.  
  321.     /* Get the nearest router and place the address of the router in the  */
  322.     /* ECB field "ImmediateAddress" */
  323.     IPXGetLocalTarget(     (unsigned char *)sPacket->Destination.Network,
  324.         (unsigned char *)sECB->ImmediateAddress, transportTime );
  325.     sPacket->Destination.Socket = ConnectSocket;
  326.  
  327.     printf("\nHit any key to quit this connection.\n");
  328.     while ( !kbhit() ) {
  329.         SPXSendSequencedPacket( connectionID, sECB );
  330.  
  331.         /* I loop here because I shouldn't touch the ECB until IPX/SPX has  */
  332.         /* finished with it.  IPX/SPX is done with the ECB when the InUseFlag */
  333.         /* is set to zero. */
  334.         while ( sECB->InUseFlag )
  335.             IPXRelinquishControl();
  336.         switch ( sECB->CompletionCode ) {
  337.         case 0x00:
  338.             break;
  339.         case 0xED:        /* Connection died. */
  340.             printf("\nConnection failed.  Exiting.\n");
  341.             exit (-1);
  342.             break;
  343.         case 0xEE:        /* Connection was terminated. */
  344.             printf("\nConnection was terminated by the other side.\n");
  345.             exit (0);
  346.             break;
  347.         default:
  348.             printf("\nError occurred during my send loop. ccode: %0x\n",
  349.                 sECB->CompletionCode );
  350.             exit (-1);
  351.             break;
  352.         }
  353.         printf("%08lx\r", SendStats+1 );
  354.     }
  355.     /* To clean up we should terminate the connection. */
  356.     TerminateTheConnection( connectionID );
  357.  
  358. }
  359.  
  360. /*
  361. **  This procedure puts some Event Control Blocks (ECBs) out for SPX to use.
  362. **  These ECBs will later be used, if the program is acting as receiver, to
  363. **  listen for incoming packets.  When a packet is received SPX will activate
  364. **  the associated Event Service Routine (ReceiveESRHandler).  In this case
  365. **  the Event Service Routine is contained in an assembly program
  366. **  (Connecta.asm) which will call a 'C' procedure (ReceiveESR()).
  367. **  The assembly module simply pushes the address of the ECB on the stack
  368. **  then calls the 'C' module.
  369. **
  370. **    See the document "Peer-To-Peer" protocols for a description of what
  371. **    fields must be initialized in the ECB before issuing an
  372. **    SPXListenForSequencedPacket();
  373. **
  374. **    NOTE:     Some ECBs must be allocated even if you are the sender.  SPX needs
  375. **           them for its pool of availible ECBs.  This is IMPORTANT!!  You must
  376. **            have this pool of ECBs available for SPX.  SPX uses them to
  377. **            implement the flow control and guarnteed delivery services.
  378. **            A pool of 2 would be the minimum but more is suggested.  In this
  379. **            program I use a pool of 5.
  380. */
  381. GiveSPXAnListenECBPool()
  382. {
  383.     ECB            *wECB;
  384.     SPXPacket    *sPacket;
  385.     char        far *farCharPointer, *data;
  386.     int            i=0;
  387.     void        ReceiveESRHandler();
  388.  
  389.     while ( i++ != 5 ) {
  390.         if ( (wECB = (ECB *)myalloc( 1, sizeof( ECB )) ) == NULL ) {
  391.             printf("Out of memory allocating space for ECB.\n");
  392.             exit (-1);
  393.         }
  394.         if ( (sPacket = (SPXPacket *)myalloc( 1, sizeof( SPXPacket )) ) == NULL ) {
  395.             printf("Out of memory allocating space for SPXPacket.\n");
  396.             exit (-1);
  397.         }
  398.         data = (char *)myalloc( 1, DATASIZE );
  399.  
  400.         farCharPointer = (char far *)ReceiveESRHandler;
  401.         wECB->ESRAddress = farCharPointer;
  402.         wECB->ECBSocket = ConnectSocket;
  403.  
  404.         /* I will have two fragments in this program.  This is not a */
  405.         /* requirement.  You could implement with 1 fragment or more */
  406.         /* than 2.  It is up to the programmer.  You will notice that */
  407.         /* the first fragment contains the SPXPacket header.  This is a */
  408.         /* requirement.  My second fragment will contain the data I am  */
  409.         /* sending.  In this program this is bogus information.  */
  410.         wECB->FragmentCount = 2;
  411.         farCharPointer = (char far *)sPacket;
  412.         wECB->FragmentDescriptor[0].Address = farCharPointer;
  413.         wECB->FragmentDescriptor[0].Size = sizeof( SPXPacket );
  414.         farCharPointer = (char far *)data;
  415.         wECB->FragmentDescriptor[1].Address = farCharPointer;
  416.         wECB->FragmentDescriptor[1].Size = DATASIZE;
  417.         sPacket->PacketType = (char)5;
  418.         sPacket->PacketLength = IntSwap( sizeof( SPXPacket ) );
  419.  
  420.         SPXListenForSequencedPacket( wECB );
  421.     }
  422.  
  423. }
  424.  
  425. /*
  426. **    This function terminates a connection.
  427. */
  428. TerminateTheConnection( connectionID )
  429. int        connectionID;
  430. {
  431.     ECB            *wECB;
  432.     SPXPacket    *sPacket;
  433.     char        far *farCharPointer;
  434.  
  435.     if ( (wECB = (ECB *)myalloc( 1, sizeof( ECB )) ) == NULL ) {
  436.         printf("Out of memory allocating space for ECB.\n");
  437.         exit (-1);
  438.     }
  439.     if ( (sPacket = (SPXPacket *)myalloc( 1, sizeof( SPXPacket )) ) == NULL ) {
  440.         printf("Out of memory allocating space for SPXPacket.\n");
  441.         exit (-1);
  442.     }
  443.     wECB->ECBSocket = ConnectSocket;
  444.     wECB->FragmentCount = 1;
  445.     farCharPointer = (char far *)sPacket;
  446.     wECB->FragmentDescriptor[0].Address = farCharPointer;
  447.     wECB->FragmentDescriptor[0].Size = sizeof( SPXPacket );
  448.     sPacket->PacketType = (char)5;    /* SPX Packet */
  449.     sPacket->PacketLength = IntSwap( sizeof( SPXPacket ) );
  450.  
  451.     SPXTerminateConnection( connectionID, wECB );
  452.  
  453.     /* I loop here because I shouldn't touch the ECB until IPX/SPX has  */
  454.     /* finished with it.  IPX/SPX is done with the ECB when the InUseFlag */
  455.     /* is set to zero. */
  456.     while ( wECB->InUseFlag )
  457.         IPXRelinquishControl();
  458.  
  459. }
  460.  
  461.  
  462. /*
  463. **  This Event Service Routine is activated when a packet is received on
  464. **  the appropiate socket.
  465. **
  466. **    Remember that this program is called from an assembly program
  467. **        called "ReceiveESRHandler".  That procedure puts the address
  468. **        of the ECB on the stack and calls this procedure.  This is just
  469. **        the way I decided to implement it.  There are other options
  470. **        available to you.
  471. */
  472. void ReceiveESR( wECB )
  473. ECB        *wECB;
  474. {
  475.     /* I simply increment a counter and put the ECB in the Listen pool again */
  476.     ReceiveStats++;
  477.     SPXListenForSequencedPacket( wECB );
  478. }
  479.  
  480. /*
  481. **  Increments a global variable.
  482. */
  483. void SendESR( wECB )
  484. ECB        *wECB;
  485. {
  486.     SendStats++;
  487. }
  488.  
  489.